package com.xxx.mch.service.impl;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.xxx.mch.dao.TaskScoreMapper;
import com.xxx.mch.dao.TaskScoreTemplateMapper;
import com.xxx.mch.dao.UsedScoreTemplateMapper;
import com.xxx.mch.domain.dto.GenresTemplateDto;
import com.xxx.mch.domain.dto.TaskScoreTemplateDto;
import com.xxx.mch.domain.po.BusinessStatistics;
import com.xxx.mch.domain.po.TaskScore;
import com.xxx.mch.domain.po.TaskScoreTemplate;
import com.xxx.mch.domain.po.TotalScore;
import com.xxx.mch.domain.po.UsedScoreTemplate;
import com.xxx.mch.domain.request.CreateScoreRequest;
import com.xxx.mch.domain.request.QueryScoreRequest;
import com.xxx.mch.domain.request.RuleSearchRequest;
import com.xxx.mch.domain.request.TaskScoreTemplateRequest;
import com.xxx.mch.exception.BusinessException;
import com.xxx.mch.service.GenresService;
import com.xxx.mch.service.TaskScoreService;
import java.math.BigDecimal;
import javax.annotation.Resource;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import tk.mybatis.mapper.weekend.Weekend;
import tk.mybatis.mapper.weekend.WeekendCriteria;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @author FengHaixin
 * @description 一句话描述该文件的用途
 * @date 2020-02-25
 */
@Service
public class TaskScoreServiceImpl implements TaskScoreService
{
    @Autowired
    private ApplicationContext applicationContext;

    @Resource
    private TaskScoreMapper taskScoreMapper;

    @Resource
    private TaskScoreTemplateMapper taskScoreTemplateMapper;

    @Resource
    private UsedScoreTemplateMapper usedScoreTemplateMapper;

    @Resource
    private GenresService genresService;

    @Autowired
    private BusinessStatisticsImpl businessStatisticsImpl;


    @Override
    @Transactional (rollbackFor = Exception.class)
    public void createScoreRecord(CreateScoreRequest scoreRequest)
    {
        BusinessStatistics bs = new BusinessStatistics();

        Weekend<TaskScoreTemplate> weekend = new Weekend<>(TaskScoreTemplate.class);
        WeekendCriteria<TaskScoreTemplate, Object> criteria = weekend.weekendCriteria();
        criteria.andEqualTo(TaskScoreTemplate::getId, scoreRequest.getTaskId());
        TaskScoreTemplate parentTemplate = taskScoreTemplateMapper.selectByPrimaryKey(scoreRequest.getTaskId());
        bs.setTaskTemplateId(parentTemplate.getParentId());
        bs.setStatus(scoreRequest.getScoreType() == 1 ? true :false);
        bs.setUid(scoreRequest.getUid());
        businessStatisticsImpl.saveBusinessStatistics(bs);
        if (scoreRequest.getScoreType() == 1)
        {
            TaskScore taskScore = new TaskScore();
            BeanUtils.copyProperties(scoreRequest, taskScore);
            TaskScoreTemplate template = taskScoreTemplateMapper.selectByPrimaryKey(taskScore.getLevelId());
            if (template == null)
            {
                throw new BusinessException("模板细则不存在，id=" + taskScore.getLevelId());
            }
            if (Objects.isNull(template.getMaxScore()) || Objects.isNull(template.getMinScore()))
            {
                throw new BusinessException("模板细则完成分或逾期分不存在， id=" + taskScore.getLevelId());
            }
            if (taskScore.getCompletionTime().compareTo(taskScore.getPlanCompletionTime()) > 0)
            {
                taskScore.setScore(template.getMinScore());
            }
            else
            {
                taskScore.setScore(template.getMaxScore());
            }
            if (Objects.nonNull(scoreRequest.getGenresId()))
            {
                GenresTemplateDto genresServiceTemplate = genresService.getTemplate(scoreRequest.getGenresId());
                taskScore.setGenresId(genresServiceTemplate.getId());
                taskScore.setGenresScore(new BigDecimal(genresServiceTemplate.getScore()));
            }
            else
            {
                taskScore.setGenresScore(BigDecimal.ZERO);
            }
            taskScoreMapper.insertSelective(taskScore);
            TotalScore totalScore = new TotalScore();
            totalScore.setUid(taskScore.getUid());
            if (Objects.isNull(taskScore.getUsedScore()))
            {
                taskScore.setUsedScore(BigDecimal.ZERO);
            }
            if (Objects.isNull(taskScore.getGenresScore()))
            {
                taskScore.setGenresScore(BigDecimal.ZERO);
            }
            totalScore.setAllowanceScore(taskScore.getScore().add(taskScore.getUsedScore()).add(taskScore.getGenresScore()));
            totalScore.setTaskScore(taskScore.getScore());
            applicationContext.publishEvent(totalScore);
        }
        else if (scoreRequest.getScoreType() == 2)
        {
            UsedScoreTemplate template = usedScoreTemplateMapper.selectByPrimaryKey(scoreRequest.getLevelId());
            if (template == null)
            {
                throw new BusinessException("采用分模板细则不存在，id=" + scoreRequest.getLevelId());
            }
            TaskScore taskScore = new TaskScore();
            BeanUtils.copyProperties(scoreRequest, taskScore);
            taskScore.setUsedScore(template.getScore());
            taskScoreMapper.insertSelective(taskScore);
            TotalScore totalScore = new TotalScore();
            totalScore.setUid(scoreRequest.getUid());
            totalScore.setAllowanceScore(taskScore.getUsedScore());
            applicationContext.publishEvent(totalScore);
        }

    }


    @Override
    public PageInfo<TaskScore> queryScoreRecord(QueryScoreRequest queryScoreRequest)
    {
        Page<TaskScore> page = PageHelper.startPage(queryScoreRequest.getPage(), queryScoreRequest.getPageSize());
        PageInfo<TaskScore> pageInfo = page.doSelectPageInfo(() -> {
            Weekend<TaskScore> weekend = new Weekend<>(TaskScore.class);
            WeekendCriteria<TaskScore, Object> criteria = weekend.weekendCriteria();
            criteria.andEqualTo(TaskScore::getUid, queryScoreRequest.getUid());
            criteria.andCondition(
                    "DATE_FORMAT(STR_TO_DATE(plan_completion_time,\"%Y-%m-%d %H:%i:%s\"), '%Y-%m')= '" + queryScoreRequest.getDate() + "'");
            if (!CollectionUtils.isEmpty(queryScoreRequest.getFilters()))
            {
                criteria.andIn(TaskScore::getTaskId, queryScoreRequest.getFilters());
            }
            taskScoreMapper.selectByExample(weekend);
        });
        return pageInfo;
    }


    @Override
    public List<TaskScore> queryTaskTypes(QueryScoreRequest queryScoreRequest)
    {
        return taskScoreMapper.selectTaskType(queryScoreRequest);
    }


    @Override
    public void createOrUpdateTemplate(List<TaskScoreTemplateRequest> templateRequestList)
    {
        if (CollectionUtils.isEmpty(templateRequestList))
        {
            return;
        }

        templateRequestList.forEach(this::doCreateOrUpdateTemplate);
    }


    @Override
    public void deleteTemplate(Integer templateId)
    {
        List<TaskScoreTemplate> templateList = taskScoreTemplateMapper.select(new TaskScoreTemplate().setParentId(templateId));
        if (!CollectionUtils.isEmpty(templateList))
        {
            throw new BusinessException("该菜单下还有子菜单，请先删除子菜单");
        }
        taskScoreTemplateMapper.deleteByPrimaryKey(templateId);
    }


    @Override
    public List<TaskScoreTemplateDto> getTaskTemplate(List<Integer> parentId, Integer depth, Boolean status, Boolean showHeader)
    {
        //先查询根，parentId是空的
        Weekend<TaskScoreTemplate> weekend = new Weekend<>(TaskScoreTemplate.class);
        WeekendCriteria<TaskScoreTemplate, Object> criteria = weekend.weekendCriteria();

        if (CollectionUtils.isEmpty(parentId))
        {
            criteria.andIsNull(TaskScoreTemplate::getParentId);
        }
        else
        {
            criteria.andIn(TaskScoreTemplate::getId, parentId);
        }
        List<TaskScoreTemplate> templates = taskScoreTemplateMapper.selectByExample(weekend);
        List<TaskScoreTemplateDto> taskScoreTemplateDtoList = this.convert(templates);
        this.querySubContext(taskScoreTemplateDtoList, --depth, status, showHeader);
        return taskScoreTemplateDtoList;
    }


    @Override
    public List<TaskScoreTemplateDto> ruleSearch(RuleSearchRequest ruleSearchRequest)
    {
        Weekend<TaskScoreTemplate> weekend = new Weekend<>(TaskScoreTemplate.class);
        WeekendCriteria<TaskScoreTemplate, Object> criteria = weekend.weekendCriteria();
        criteria.andEqualTo(TaskScoreTemplate::getParentId, ruleSearchRequest.getParentId());
        criteria.andLike(TaskScoreTemplate::getName, "%" + ruleSearchRequest.getName() + "%");
        return this.convert(taskScoreTemplateMapper.selectByExample(weekend));
    }


    @Override
    public List<TaskScoreTemplateDto> ruleQuery(Integer type)
    {
        List<TaskScoreTemplate> taskScoreTemplates = taskScoreTemplateMapper.select(new TaskScoreTemplate().setType(type));
        if (CollectionUtils.isEmpty(taskScoreTemplates))
        {
            return new ArrayList<>();
        }
        List<Integer> parentIdList = taskScoreTemplates.stream().map(TaskScoreTemplate::getId).collect(Collectors.toList());
        return this.getTaskTemplate(parentIdList, 3, true, true).stream().flatMap(
                taskScoreTemplateDto -> taskScoreTemplateDto.getChildren().stream()).collect(Collectors.toList());
    }


    private void querySubContext(List<TaskScoreTemplateDto> templates, Integer depth, Boolean status, Boolean showHeader)
    {
        //终止条件
        if (CollectionUtils.isEmpty(templates) || depth <= 0)
        {
            return;
        }

        for (TaskScoreTemplateDto taskScoreTemplate : templates)
        {
            List<TaskScoreTemplate> subContextList = taskScoreTemplateMapper.select(new TaskScoreTemplate().setParentId(
                    taskScoreTemplate.getId()).setStatus(status).setShowBusinessHeader(showHeader));
            //设置为下一级
            List<TaskScoreTemplateDto> taskScoreTemplateDtoList = this.convert(subContextList);
            taskScoreTemplate.setChildren(taskScoreTemplateDtoList);
            this.querySubContext(taskScoreTemplateDtoList, --depth, status, showHeader);
            ++depth;
        }
    }


    private List<TaskScoreTemplateDto> convert(List<TaskScoreTemplate> templates)
    {
        return templates.stream().map(taskScoreTemplate -> {
            TaskScoreTemplateDto templateDto = new TaskScoreTemplateDto();
            BeanUtils.copyProperties(taskScoreTemplate, templateDto);
            return templateDto;
        }).collect(Collectors.toList());
    }


    private void doCreateOrUpdateTemplate(TaskScoreTemplateRequest templateRequest)
    {
        TaskScoreTemplate template = new TaskScoreTemplate();
        BeanUtils.copyProperties(templateRequest, template);

        if (this.isCreate(templateRequest))
        {
            this.doCreate(template);
        }
        else
        {
            this.doUpdate(template);
        }

        List<TaskScoreTemplateRequest> subContext = templateRequest.getChildren();
        if (CollectionUtils.isEmpty(subContext))
        {
            return;
        }
        subContext.forEach(taskScoreTemplate -> {
            taskScoreTemplate.setParentId(template.getId());
            this.doCreateOrUpdateTemplate(taskScoreTemplate);
        });

    }


    private void doUpdate(TaskScoreTemplate template)
    {
        //template.setType();
        taskScoreTemplateMapper.updateByPrimaryKeySelective(template);

    }


    private void doCreate(TaskScoreTemplate template)
    {
        template.setStatus(true);
        taskScoreTemplateMapper.insertSelective(template);
    }


    private boolean isCreate(TaskScoreTemplateRequest templateRequest)
    {
        return Objects.isNull(templateRequest.getId());
    }
}
